#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>
#include "Log.hpp"
#include "Common.hpp"

using namespace LogMoudle;

const std::string Sep = "\r\n";
const std::string LineSep = " ";
const std::string HeaderLineSep = ":";
const std::string BlankLine = Sep;
const std::string defaulthomepage = "wwwroot";
const std::string http_version = "HTTP/1.0";
const std::string page404 = "wwwroot/404.html";
const std::string firstpage = "index.html";

// GET /favicon.ico HTTP/1.1\r\n
// Host: 8.137.19.140:8080
// Connection: keep-alive
// User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0
// Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
// Referer: http://8.137.19.140:8080/?msg=i_have_sent_a_message_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_
// Accept-Encoding: gzip, deflate
// Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
// dnt: 1
// sec-gpc: 1
//

// 对于请求的反序列化
class HttpRequest
{

 public:
   HttpRequest() {}
   ~HttpRequest() {}

    bool IsHasArgs()
    {
        return _isexec;
    }

    // 二次分解请求报头
    bool ParseHeaderkv()
    {
        std::string key, value;
        for (auto &header : _req_header)
        {
            if (SplitString(header,HeaderLineSep, &key, &value))
            {
                _headerkv.insert(std::make_pair(key, value));
            }
        }

        return true;
    }

    bool ParseHeader(std::string &request_str)
    {
        std::string line;
        while (true)
        {
            bool r = ParseOneLine(request_str, &line, Sep);
            if (r && !line.empty())
            {
                _req_header.push_back(line);
            }
            else if (r && line.empty())
            {
                _blank_line = Sep;
                break;
            }
            else
            {
                return false;
            }
        }

        ParseHeaderkv();

        return true;
    }

    void Deserialize(std::string &request_str)
    {
        // 获取请求行
        if (ParseOneLine(request_str, &_req_line, Sep))
        {
            // 提取请求行中的详细字段
            ParseReqLine(_req_line, LineSep);

            // 处理请求报头
            ParseHeader(request_str);

            _body = request_str;

            // 分参数当中是否含有参数
            if (_method == "POST")
            {
                _isexec = true; // 参数正文

                _args = _body;
                _path = _uri;
                LOG(Logevel::INFO) << "POST: _path: " << _path;
                LOG(Logevel::INFO) << "POST: _args: " << _args;
            }
            else if (_method == "GET")
            {
                auto pos = _uri.find("?");

                if (pos != std::string::npos)
                {
                    _isexec = true;

                    _path = _uri.substr(0, pos);
                    _args = _uri.substr(pos + 1);

                    LOG(Logevel::INFO) << "GET: _path: " << _path;
                    LOG(Logevel::INFO) << "GET: _args: " << _args;
                }
            }
        }
    }

    std::string GetContent(const std::string path)
    {
        std::string content;

        // 读取文件内容
        LOG(Logevel::INFO)<<"文件路径： "<<path;

        std::ifstream in(path, std::ios::binary);

        if (!in.is_open())
        {
            return std::string();
        }

        // 将文件的读取位置定位到文件末尾
        in.seekg(0, in.end);

        int filesize = in.tellg(); // 获取文件字符长度

        in.seekg(0, in.beg);

        content.resize(filesize);

        in.read((char *)content.c_str(), filesize); // 从数据流中读取数据到content中
        in.close();
        LOG(Logevel::INFO) << "content length: " << content.size();
        return content;
    }

    void Print()
    {
        std::cout << "_method: " << _method << std::endl;
        std::cout << "_uri: " << _uri << std::endl;
        std::cout << "_version: " << _version << std::endl;

        for (auto &kv : _headerkv)
        {
            std::cout << kv.first << "#" << kv.second << std::endl;
        }

        std::cout << "blank_line: " << _blank_line << std::endl;
        std::cout << "body: " << _body << std::endl;
    }

    std::string Uri()
    {
        return _uri;
    }

    void SetUri(const std::string newuri)
    {
        _uri = newuri;
    }

    std::string Path()
    {
        return _path;
    }

    std::string Args()
    {
        return _args;
    }

    // 读取数据的类型
    std::string Suffix()
    {
        auto pos = _uri.rfind(".");
        if (pos == std::string::npos)
        {
            return std::string(".html");
        }
        else
        {
            return _uri.substr(pos);
        }
    }

 private:
    void ParseReqLine(std::string &_req_line, const std::string sep)
    {
        (void)sep;

        // 创建一个字符串读取流ss，读取_req_line,遇到空格就会结束一次读取
        std::stringstream ss(_req_line);
        ss >> _method >> _uri >> _version;
    }

 private:
    // 对于请求行存储
    std::string _req_line;

    // 对于请求报头的存储
    std::vector<std::string> _req_header;

    // 空行
    std::string _blank_line;

    std::string _body; // 对于正文的存储，内部可能含有参数

    // 在反序列化的过程中，细化我们解析出来的字段
    std::string _method; // 请求方法

    std::string _uri; // 用户需要这个，URL

    std::string _path; // 请求路径

    std::string _args; // 参数

    std::string _version; // 版本号

    std::unordered_map<std::string, std::string> _headerkv; // 请求报头中对应的key和value

    bool _isexec; // 判断是否有参数需要处理
};

// 对于回复的数据进行序列化
class HttpReponse
{

public:
    HttpReponse() : _version(http_version), _blank_line(Sep)
    {
    }
    ~HttpReponse() {}

    // 通过对接受数据反序列化后的数据，进行发送数据的序列化
    void Build(HttpRequest &req)
    {
        //添加上相对路径

        std::string uri = defaulthomepage + req.Uri();

        if (uri.back() == '/')
        {
            //跳转到默认页面
            uri += firstpage;
        }

        LOG(Logevel::INFO) << "-----------------客户端在请求： " << req.Uri();
        req.Print();
        LOG(Logevel::INFO) << "------------------------------";

        //读取相应路径文件的数据
        _content = req.GetContent(uri);

        if (_content.empty())
        {
            _status_code = 404;

            _content = req.GetContent(page404);
        }
        else
        {
            _status_code = 200;
        }

        //相应的状态和状态码对应
        _status_desc = Code2Desc(_status_code);
        if (!_content.empty())
        {
            SetHeader("Content-Length", std::to_string(_content.size()));
        }
        std::string mime_type = Suffix2Desc(req.Suffix());

        //数据类型
        SetHeader("Content-Type",req.Suffix());
        _body=_content;
    }

    void Setcode(int code)
    {
        _status_code = code;
        _status_desc = Code2Desc(code);
    }

    void SetBody(std::string &body)
    {
        _body = body;
    }

    void SetHeader(const std::string &k, const std::string &v)
    {
        _header_kv[k] = v;
    }

    void Serialize(std::string *resp_str)
    {

        //将相应的请求报头进行还原
        for (auto &header : _header_kv)
        {
            _resp_header.push_back(header.first + HeaderLineSep + header.second);
        }

        _resp_line = _version + LineSep + std::to_string(_status_code) + LineSep + _status_desc + Sep;

        // 序列化
        *resp_str = _resp_line;
        for (auto line : _resp_header)
        {
            *resp_str += (line + Sep);
        }
        *resp_str += _blank_line;
        *resp_str += _body;
    }

private:
    std::string Code2Desc(int code)
    {

        switch (code)
        {
        case 200:
            return "OK";
        case 404:
            return "NOT FOUND";
        case 301:
            return "Moved Permanently";
        case 302:
            return "Found";
        default:
            return std::string();
        }
    }

    std::string Suffix2Desc(const std::string &suffix)
    {
        if (suffix == ".html")
            return "text/html";
        else if (suffix == ".jpg")
            return "application/x-jpg";
        else
            return "text/html";
    }

private:
    std::string _version;//版本
    int _status_code;//相应码
    std::string _status_desc;//状态描述
    std::string _content;//相应内容
    std::unordered_map<std::string, std::string> _header_kv;//相应键值

    // 最后构建应答的部分

    std::string _resp_line;
    std::vector<std::string> _resp_header;
    std::string _blank_line;
    std::string _body;
};